#include <gfx/dx12/command.h>

primal::gfx::Command::Command() :fence_value{}
{
	DXASSERT(device()->CreateFence(fence_value, D3D12_FENCE_FLAG_NONE, IIDPPV(fence)));
}

primal::gfx::ID3D12GraphicsCommandListN* primal::gfx::Command::Internal_AcquireNextList(Frame* frm, D3D12_COMMAND_LIST_TYPE TYPE, ID3D12PipelineState* pipeline)
{
	auto& cur_frame{ *frm };
	ID3D12GraphicsCommandList6* temp_list;
	if (cur_frame.list_cache.empty())
	{
		DXASSERT(device()->CreateCommandList1(0u, TYPE, D3D12_COMMAND_LIST_FLAG_NONE, IID_PPV_ARGS(&temp_list)));
	}
	else
	{
		temp_list = cur_frame.list_cache.front();
		cur_frame.list_cache.pop();
	}
	temp_list->Reset(cur_frame.allocator.Get(), pipeline);
	cur_frame.active_lists.push_back(temp_list);
	return temp_list;
}

void primal::gfx::Command::WaitFrame(HANDLE e, u64 fv)
{
	if (this->fence->GetCompletedValue() < fv)
	{
		this->fence->SetEventOnCompletion(fv, e);
		WaitForSingleObject(e, INFINITE);
	}
}

void primal::gfx::Command::Flush()
{
	auto e{ CreateEventA(nullptr, FALSE, FALSE, nullptr) };
	assert(e != nullptr);
	WaitFrame(e, this->fence_value);
	CloseHandle(e);
}

primal::gfx::Frame::Frame() :
	allocator{},
	list_cache{},
	active_lists{},
	local_fence_event{},
	local_fence_value{}
{}
